﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using GameEngine.Clients.Silverlight.Controller;
using GameEngine.Clients.Silverlight.View;
using GameEngine.Clients.Silverlight.View.Components;
using GameEngine.Model;
using GameEngine.Model.Data;
using GameEngine.Model.Data.implementation;
using GameEngine.View;
using MapEngine;
using GameEngine.View.Components;

namespace GameEngine.Clients.Silverlight
{
    public class SampleSilverlightFacade:SilverlightFacade
    {
        override protected void CreateViewFacade()
        {
            new SampleSilverlightViewFacade();
        }
    }

    public class SampleSilverlightViewFacade : SilverlightViewFacade
    {
        public override IGameView<int, FrameworkElement> CreateGameView()
        {
            return new GameUC();
        }

        public override ILevelView<int, FrameworkElement> CreateLevelView()
        {
            return new LevelUC();
        }
    }

    //<summary>
    //A base Singleton <c>IFacade</c> implementation
    //</summary>
    //<remarks>
    //    <para>In PureMVC, the <c>Facade</c> class assumes these responsibilities:</para>
    //    <list type="bullet">
    //        <item>Initializing the <c>Model</c>, <c>View</c> and <c>Controller</c> Singletons</item>
    //        <item>Providing all the methods defined by the <c>IModel, IView, &amp; IController</c> interfaces</item>
    //        <item>Providing the ability to override the specific <c>Model</c>, <c>View</c> and <c>Controller</c> Singletons created</item>
    //        <item>Providing a single point of contact to the application for registering <c>Commands</c> and notifying <c>Observers</c></item>
    //    </list>
    public abstract class SilverlightFacade : ApplicationFacade
    {
        // Notification constants. The Facade is the ideal
        // location for these constants, since any part
        // of the application participating in PureMVC 
        // Observer Notification will know the Facade.
        private const string SL_STARTUP_COMMAND = "SL_STARTUP_COMMAND";
        //public const string STARTEDITOR_COMMAND = "silverlightStartEditorCommand";

        // Override Singleton Factory method 
        //public new static SilverlightFacade<MyGameView, MyLevelView> Instance
        //{
        //    get
        //    {
        //        return ApplicationFacade.Instance as SilverlightFacade<MyGameView, MyLevelView>;
        //    }
        //}

        override protected void CreateModelFacade()
        {
            new SilverlightModelFacade();
        }

        // optional initialization hook for Facade
        protected override void InitializeFacade()
        {
            base.InitializeFacade();
            // do any special subclass initialization here
        }

        // optional initialization hook for Controller
        protected override void InitializeController()
        {
            // call base to use the PureMVC Controller Singleton. 
            base.InitializeController();

            // do any special subclass initialization here
            // such as registering Commands
            RegisterCommand(SL_STARTUP_COMMAND, typeof(SilverlightStartupCommand));
            //RegisterCommand(STARTEDITOR_COMMAND, typeof(EditorStartupCommand));
        }

        // optional initialization hook for Model
        protected override void InitializeModel()
        {
            // call base to use the PureMVC Model Singleton. 
            base.InitializeModel();

            // do any special subclass initialization here
            // such as creating and registering Model proxys
            // that don't require a facade reference at
            // construction time, such as fixed type lists
            // that never need to send Notifications.
            //RegisterProxy( new USStateNamesProxy() );

            // CAREFUL: Can't reference Facade instance in constructor 
            // of new Proxys from here, since this step is part of
            // Facade construction!  Usually, Proxys needing to send 
            // notifications are registered elsewhere in the app 
            // for this reason.
        }

        // optional initialization hook for View
        protected override void InitializeView()
        {
            // call base to use the PureMVC View Singleton. 
            base.InitializeView();

            // do any special subclass initialization here
            // such as creating and registering Mediators
            // that do not need a Facade reference at construction
            // time.
            //RegisterMediator( new LoginMediator() ); 

            // CAREFUL: Can't reference Facade instance in constructor 
            // of new Mediators from here, since this is a step
            // in Facade construction! Usually, all Mediators need 
            // receive notifications, and are registered elsewhere in 
            // the app for this reason.
        }

        /// <summary>
        /// Start the application
        /// </summary>
        /// <param name="app">Application (App.xml)</param>
        /// <param name="useDesktop">Use or not the DesktiopMediator who controls the mainscreen</param>
        /// <param name="firstScreen">The first UserControl to show</param>
        virtual public void Start(Application app, bool useDesktop, FrameworkElement firstScreen)
        {
            SendNotification(SL_STARTUP_COMMAND, app);
            if (useDesktop)
            {
                DesktopMediator desktopMed = new DesktopMediator();
                RegisterMediator(desktopMed);
                SendNotification(AppMediator.SET_ROOTVISUAL_NOTIFICATION, desktopMed.ViewComponent);
                SendNotification(DesktopMediator.SET_SCREEN, firstScreen);
            }
            else
            {
                SendNotification(AppMediator.SET_ROOTVISUAL_NOTIFICATION, firstScreen);
            }
            //Storyboard gameLoop = new Storyboard();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="screen">(não é mediator para podermos usar sem mvc)</param>
        public void SetScreen(FrameworkElement screen)
        {
            SendNotification(DesktopMediator.SET_SCREEN, screen);
        }

        public void ManageMenu()
        {
            //TODO MenuMediator para n mvcs
        }

        public void saveGame()
        {
            var game = ModelFacade<int>.Instance.Game;

            SaveFileDialog sd = new SaveFileDialog();
            if (sd.ShowDialog().Value)
            {
                string output = game.VO.Serialize();
                TextWriter w = new StreamWriter(sd.OpenFile());
                w.Write(output);
                w.Flush();
                w.Close();
            }
        }
    }

    public class SilverlightApplicationFacadeHelper : ApplicationFacadeHelper<int>
    {

        public static void DesktopNavigate(FrameworkElement firstScreen)
        {
            ApplicationFacade.Instance.SendNotification(DesktopMediator.SET_SCREEN, firstScreen);
        }
    }

    public abstract class SilverlightViewFacade : ViewFacade<int, FrameworkElement>
    {
        protected override void RegisterShapeTypes()
        {
            base.RegisterShapeTypes();
            ShapeTypeVO uploadedImage = new ShapeTypeVO(new ShapeTypeVOId(ItemUC.ShapeTypeUploadedImage));
            SilverlightModelFacade.Instance.ShapeTypes.Add(uploadedImage.Id, uploadedImage);

            ShapeTypeVO projectImage = new ShapeTypeVO(new ShapeTypeVOId(ItemUC.ShapeTypeProjectImage));
            SilverlightModelFacade.Instance.ShapeTypes.Add(projectImage.Id, projectImage);

            ShapeTypeVO resourceImage = new ShapeTypeVO(new ShapeTypeVOId(ItemUC.ShapeTypeGameResourceImage));
            SilverlightModelFacade.Instance.ShapeTypes.Add(resourceImage.Id, resourceImage);

            ShapeTypeVO sprite = new ShapeTypeVO(new ShapeTypeVOId(ItemUC.ShapeTypeSprite));
            SilverlightModelFacade.Instance.ShapeTypes.Add(sprite.Id, sprite);

            ShapeTypeVO cube = new ShapeTypeVO(new ShapeTypeVOId(ItemUC.ShapeTypeCube));
            SilverlightModelFacade.Instance.ShapeTypes.Add(cube.Id, cube);

            ShapeTypeVO triangle = new ShapeTypeVO(new ShapeTypeVOId(ItemUC.ShapeTypePyramid));
            SilverlightModelFacade.Instance.ShapeTypes.Add(triangle.Id, triangle);

            ShapeTypeVO elipse = new ShapeTypeVO(new ShapeTypeVOId(ItemUC.ShapeTypeElipse));
            SilverlightModelFacade.Instance.ShapeTypes.Add(elipse.Id, elipse);
        }

        override public WorldMediator<int, FrameworkElement> CreateWorldMediator(
            IWorldDataProxy<int> world, 
            MapMediator<int, FrameworkElement> mapMed, 
            IThingMediator<int, FrameworkElement> itemMed,
            IWorldView<int, FrameworkElement> worldView)
        {
            return new SilverlightWorldMediator(
                        world,
                        mapMed,
                        itemMed,
                        CreateWorldView());
        }

        override public MapMediator<int, FrameworkElement> CreateMapMediator(IWorldDataProxy<int> world, IMapView<int, FrameworkElement> mapView)
        {
            return new SilverlightMapMediator(
                                world,
                                mapView
                            );
        }

        override public IThingMediator<int, FrameworkElement> CreateItemMediator(IWorldDataProxy<int> world)
        {
            return new SilverlightThingMediator(world);
        }

        override public IWorldView<int, FrameworkElement> CreateWorldView()
        {
            return new WorldUC();
        }

        override public IMapView<int, FrameworkElement> CreateMapView()
        {
            return new MapUC();
        }

        override public IThingView<int, FrameworkElement> CreateViewInstance()
        {
            return new ItemUC();
        }
    }

    public class SilverlightModelFacade : ModelFacade<int>
    {
        static int currentId = 1;
        override public int CreateNewId()
        {
            return currentId++;
        }

        override public int ParseId(string id)
        {
            return int.Parse(id);
        }
    }
}
